#include "Tetris.h"

#define WINDOW_WIDTH 520
#define WINDOW_HEIGHT 640
#define ID_DOWN_TIMER 1

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
	srand(time(NULL));//随机数种子
	//设计窗口类
	WNDCLASS wc = { 0 };
	wc.style = CS_HREDRAW | CS_VREDRAW;
	wc.lpfnWndProc = WndProc;
	wc.hInstance = hInstance;
	wc.hbrBackground = CreateSolidBrush(RGB(255, 255, 255));
	wc.lpszClassName = L"tetris";
	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
	wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_TETRIS_ICON));
	//注册窗口类
	if (!RegisterClass(&wc))
	{
		MessageBox(NULL, L"窗口类注册失败", L"错误", MB_OK);
		return 0;
	}
	//创建窗口
	HWND hWnd = CreateWindow(L"tetris", L"俄罗斯方块", WS_OVERLAPPEDWINDOW, 300, 100, WINDOW_WIDTH, WINDOW_HEIGHT, NULL, NULL, hInstance, NULL);
	if (!hWnd)
	{
		MessageBox(NULL, L"窗口创建失败", L"错误", MB_OK);
		return 0;
	}
	//显示窗口
	ShowWindow(hWnd, nCmdShow);
	//更新窗口
	UpdateWindow(hWnd);
	//消息循环
	MSG msg;
	while (GetMessage(&msg, NULL, 0, 0))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
	return 0;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{


	switch (message)
	{
	case WM_TIMER:
	{
		onTimer(hWnd);
		break;
	}
	case WM_KEYDOWN:
	{
		switch (wParam)
		{
		case VK_RETURN:
		{			//开始游戏
			onReturn(hWnd);
			break;
		}
		case VK_SPACE:
			//暂停/继续
			onStop(hWnd);
			break;
		case VK_LEFT:
			MoveLeft();
			//左移
			break;
		case VK_RIGHT:
			MoveRight();
			//右移
			break;
		case VK_DOWN:
			onDown(hWnd);
			//加速
			break;
		case VK_UP:
			//旋转
			onChange();
			break;
		}
		break;
	}
	case WM_DESTROY:
	{
		PostQuitMessage(0);
		break;
	}
	case WM_PAINT:
	{
		PAINTSTRUCT ps;
		HDC hdc = BeginPaint(hWnd, &ps);
		//绘制
		DoublePaint(hdc);
		EndPaint(hWnd, &ps);
		break;
	}

	}
	return DefWindowProc(hWnd, message, wParam, lParam);
}

void onReturn(HWND hWnd)
{
	//清空游戏区域
	memset(g_arrBoard, 0, sizeof(g_arrBoard));
	//开始游戏
	CreateNext();
	CreateCurrent();
	//定时器
	SetTimer(hWnd, ID_DOWN_TIMER, 200, NULL);

}

void CreateCurrent()
{
	//清空一下数组
	memset(g_arrCurrent, 0, sizeof(g_arrCurrent));
	//生成当前方块
	memcpy(g_arrCurrent, g_arrNext, sizeof(g_arrNext));
	//初始化当前方块位置
	g_nCurrentX = 4;
	g_nCurrentY = -3;
	//生成下一个方块
	CreateNext();
	//随机旋转
	for (int i = 0; i < rand() % 4; i++)
		onChange();
}

void MoveDown()
{
	if (CanMoveDown())
		g_nCurrentY++;
	else
	{
		//固定当前方块
		for (int i = 0; i < 4; i++)
			for (int j = 0; j < 4; j++)
				if (g_arrCurrent[i][j] == 1)
					g_arrBoard[i + g_nCurrentY][j + g_nCurrentX] = 1;

		//判断是否可以消除行
		for (int i = 0; i < 20; i++)
			if (CanClearLine(i))
			{
				//消除行
				for (int j = i; j > 0; j--)
					for (int k = 0; k < 10; k++)
						g_arrBoard[j][k] = g_arrBoard[j - 1][k];
				//更新分数
				score += 10;
			}
		//重新生成当前方块
		CreateCurrent();
	}
}


bool CanMoveDown()
{
	for (int i = 0; i < 4; i++)
		for (int j = 0; j < 4; j++)
		{
			if (g_arrCurrent[i][j] == 1 && g_arrBoard[i + g_nCurrentY + 1][j + g_nCurrentX] == 1)
				return false;
			if (g_arrCurrent[i][j] == 1 && i + g_nCurrentY + 1 >= 20)
				return false;
		}
	return true;
}

void MoveLeft()
{
	if (CanMoveLeft())
		g_nCurrentX--;
}

bool CanMoveLeft()
{
	for (int i = 0; i < 4; i++)
		for (int j = 0; j < 4; j++)
		{
			if (g_arrCurrent[i][j] == 1 && g_arrBoard[i + g_nCurrentY][j + g_nCurrentX - 1] == 1)
				return false;
			if (g_arrCurrent[i][j] == 1 && j + g_nCurrentX - 1 < 0)
				return false;
		}
	return true;
}

void MoveRight()
{
	if (CanMoveRight())
		g_nCurrentX++;
}

bool CanMoveRight()
{
	for (int i = 0; i < 4; i++)
		for (int j = 0; j < 4; j++)
		{
			if (g_arrCurrent[i][j] == 1 && g_arrBoard[i + g_nCurrentY][j + g_nCurrentX + 1] == 1)
				return false;
			if (g_arrCurrent[i][j] == 1 && j + g_nCurrentX + 1 >= 10)
				return false;
		}
	return true;
}

bool CanClearLine(int nLine)
{
	for (int i = 0; i < 10; i++)
		if (g_arrBoard[nLine][i] == 0)
			return false;
	return true;
}

void onTimer(HWND hWnd)
{
	MoveDown();
	InvalidateRect(hWnd, NULL, TRUE);
	//判断游戏是否结束
	if (IsGameOver())
	{
		//关闭定时器
		KillTimer(hWnd, ID_DOWN_TIMER);
		//显示游戏结束
		if (MessageBox(hWnd, L"游戏结束，是否重新开始？", L"提示", MB_YESNO) == IDYES)
		{
			//重新开始游戏
			Reset(hWnd);
		}
		else
		{
			//退出游戏
			PostQuitMessage(0);
		}
	}
}

void onDown(HWND hWnd)
{
	while (CanMoveDown())
		MoveDown();
	InvalidateRect(hWnd, NULL, TRUE);
}

void onStop(HWND hWnd)
{
	//判断当前定时器是否开始
	if (IsStop)
	{
		//开始定时器
		SetTimer(hWnd, ID_DOWN_TIMER, 200, NULL);
		IsStop = false;
	}
	else
	{
		//关闭定时器
		KillTimer(hWnd, ID_DOWN_TIMER);
		IsStop = true;
	}
}

void onChange()
{
	if (CanRotate())
		memcpy(g_arrCurrent, arrTemp, sizeof(g_arrCurrent));
}

bool CanRotate()
{
	memcpy(arrTemp, g_arrCurrent, sizeof(g_arrCurrent));
	for (int i = 0; i < 4; i++)
		for (int j = 0; j < 4; j++)
			arrTemp[i][j] = g_arrCurrent[j][3 - i];
	for (int i = 0; i < 4; i++)
		for (int j = 0; j < 4; j++)
		{
			if (arrTemp[i][j] == 1 && g_arrBoard[i + g_nCurrentY][j + g_nCurrentX] == 1)
				return false;
			if (arrTemp[i][j] == 1 && i + g_nCurrentY >= 20)
				return false;
			if (arrTemp[i][j] == 1 && j + g_nCurrentX >= 10)
				return false;
			if (arrTemp[i][j] == 1 && j + g_nCurrentX < 0)
				return false;
		}
	return true;
}

bool IsGameOver()
{
	//判断第0行是否有方块
	for (int i = 0; i < 10; i++)
		if (g_arrBoard[0][i] == 1)
			return true;
	return false;
}

void Reset(HWND hWnd)
{
	//清空游戏区域
	memset(g_arrBoard, 0, sizeof(g_arrBoard));
	//开始游戏
	onReturn(hWnd);
	IsStop = false;
}

void onPaint(HDC hdc)
{
	RECT rc;
	int x = 0, y = 0, w = 28, h = 28;//定义矩形宽高

	HBRUSH hBrush1 = CreateSolidBrush(RGB(255, 0, 0));
	HBRUSH hBrush2 = CreateSolidBrush(RGB(0, 0, 255));
	//绘制客户区边框
	HWND hWnd = GetForegroundWindow();
	GetClientRect(hWnd, &rc);
	RoundRect(hdc, rc.left, rc.top, rc.right, rc.bottom, 10, 10);

	//绘制游戏区域边框
	rc = { 0, 0, 300, 600 };
	RoundRect(hdc, rc.left, rc.top, rc.right, rc.bottom, 10, 10);
	//绘制网格
	for (int i = 0; i < 20; i++)
	{
		for (int j = 0; j < 10; j++)
		{
			if (g_arrBoard[i][j] == 1)
			{
				//绘制矩形
				x = j * 30 + 1;
				y = i * 30 + 1;
				rc = { x, y, x + w, y + h };
				SelectObject(hdc, hBrush2);
				Rectangle(hdc, rc.left, rc.top, rc.right, rc.bottom);

			}
		}
	}
	//绘制当前方块
	for (int i = 0; i < 4; i++)
	{
		for (int j = 0; j < 4; j++)
		{
			if (g_arrCurrent[i][j] == 1)
			{
				//绘制矩形
				x = (g_nCurrentX + j) * 30 + 1;
				y = (g_nCurrentY + i) * 30 + 1;
				rc = { x, y, x + w, y + h };
				SelectObject(hdc, hBrush1);
				Rectangle(hdc, rc.left, rc.top, rc.right, rc.bottom);
			}
		}
	}
	//绘制右侧菜单
	// 绘制预览图,在320,10的位置开始绘制
	for (int i = 0; i < 4; i++)
	{
		for (int j = 0; j < 4; j++)
		{
			if (g_arrNext[i][j] == 1)
			{
				x = 320 + j * 26 + 1;
				y = 10 + i * 26 + 1;
				rc = { x, y, x + 24, y + 24 };
				SelectObject(hdc, hBrush2);
				Rectangle(hdc, rc.left, rc.top, rc.right, rc.bottom);
			}
		}
	}

	//字体
	HFONT hFont = CreateFont(26, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, L"微软雅黑");
	SelectObject(hdc, hFont);
	wchar_t szScore[10];
	wsprintf(szScore, L"分数：%d", score);//绘制分数
	TextOut(hdc, 320, 100, szScore, wcslen(szScore));//绘制分数
	TextOut(hdc, 320, 160, L"游戏说明", wcslen(L"游戏说明"));//绘制游戏说明	
	TextOut(hdc, 320, 220, L"回车键：开始游戏", wcslen(L"回车键：开始游戏"));
	TextOut(hdc, 320, 280, L"空格键：暂停/继续", wcslen(L"空格键：暂停/继续"));
	TextOut(hdc, 320, 340, L"向左键：左移", wcslen(L"向左键：左移"));
	TextOut(hdc, 320, 400, L"向右键：右移", wcslen(L"向右键：右移"));
	TextOut(hdc, 320, 520, L"向上键：旋转", wcslen(L"向上键：旋转"));
	TextOut(hdc, 320, 460, L"向下键：加速", wcslen(L"向下键：加速"));
}

void DoublePaint(HDC hdc)
{
	//创建兼容位图
	HBITMAP hBitmap = CreateCompatibleBitmap(hdc, WINDOW_WIDTH, WINDOW_HEIGHT);
	//创建内存设备上下文
	HDC hMemDC = CreateCompatibleDC(hdc);
	SelectObject(hMemDC, hBitmap);
	onPaint(hMemDC);
	BitBlt(hdc, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, hMemDC, 0, 0, SRCCOPY);
}

void CreateNext()
{
	//清空一下数组 
	memset(g_arrNext, 0, sizeof(g_arrNext));
	//生成下一个方块
	int nType = rand() % 7;
	switch (nType)
	{
	case 0://O型
	{
		g_arrNext[1][1] = 1;
		g_arrNext[1][2] = 1;
		g_arrNext[2][1] = 1;
		g_arrNext[2][2] = 1;
		break;
	}
	case 1://I型
	{
		g_arrNext[1][0] = 1;
		g_arrNext[1][1] = 1;
		g_arrNext[1][2] = 1;
		g_arrNext[1][3] = 1;
		break;
	}
	case 2://L型
	{
		g_arrNext[0][0] = 1;
		g_arrNext[1][0] = 1;
		g_arrNext[2][0] = 1;
		g_arrNext[2][1] = 1;
		break;
	}
	case 3://Z型
	{
		g_arrNext[0][1] = 1;
		g_arrNext[1][0] = 1;
		g_arrNext[1][1] = 1;
		g_arrNext[2][0] = 1;
		break;
	}
	case 4://T型
	{
		g_arrNext[0][1] = 1;
		g_arrNext[1][0] = 1;
		g_arrNext[1][1] = 1;
		g_arrNext[1][2] = 1;
		break;
	}
	case 5://J型
	{
		g_arrNext[0][1] = 1;
		g_arrNext[1][1] = 1;
		g_arrNext[2][1] = 1;
		g_arrNext[2][0] = 1;
		break;
	}
	case 6://S型
	{
		g_arrNext[0][1] = 1;
		g_arrNext[1][0] = 1;
		g_arrNext[1][1] = 1;
		g_arrNext[0][2] = 1;
		break;
	}
	}
}
